/**
 * \file execution.cpp
 * \author Ameen Jaber
 * \author Mohamad Noureddine
 * \author Mohamed Sabra
 * \brief Contains implmemention of execution methods.
 * The file contains the implementation of the execution methods that
 * will handle the execution of several algorithms in TripleP.
 */

#include<execution.h>
#include<algorithm_call.h>
 
// define weight (#define Weight 1) if weighted graph

bool execution(graphStruct * graphS, varTable_t * VTable, GraphTable_t * GraphTable, algMap_t * AlgTable) {
  TPGraph_t * graph = graphS->graph;
  revTPTable_t * revTable = graphS->Vname;
  varTable_t * table = VTable;
  GraphTable_t * gtable=GraphTable;
#ifdef Weight
  Gwmap_t pppgraph_map;
#else
  Gmap_t pppgraph_map;
#endif
  WorkQueue * Q = new WorkQueue(); 
  Q->setNumThreads(4);
  Q->initThreads();
    
  ///////// Traverse Graph ////////////
  boost::graph_traits<TPGraph_t>::vertex_iterator v, vend;
  for (tie(v, vend) = vertices(*graph); v != vend; ++v) {
    if( (*graph)[*v].op == Graph ) {
#ifdef Weight
      PPPWGraph * g= new PPPWGraph();
#else
      PPPGraph * g = new PPPGraph();
#endif
      std::string s = (*revTable)[*v];
      InDGraph * a;
      a = (*gtable)[s];
      pppset * vertices=(pppset*)((*table)[a->V_name]);
      int vsize = vertices->data->size();
      for (int i = 0 ; i < vsize ; i++) {
	g->nodes.push_back(new PPPNode((*(vertices->data))[i]->val)); // add num_vertices nodes to graph
#ifdef Weight
	g->edges.push_back(new std::vector <PPPWEdge>()); // allocate edge vector for vertices
#else 
	g->edges.push_back(new std::vector <PPPEdge>()); 
#endif
      }

      // build edges
      ppprelation * edges = (ppprelation *)((*table)[a->E_name]);
      pppfunction * weights = (pppfunction*)((*table)[a->W_name]);
      int to, from, w;
      int size = edges->data->size();
      for (int i = 0 ; i < size ; i++) {
	from = edges->data->at(i)->first->val;
	to = edges->data->at(i)->second->val;
#ifdef Weight
	PPPWEdge E1, E2; 
#else 
	PPPEdge E1, E2;
#endif
	E1.to = to; 
	E2.to = from;
#ifdef Weight
	w = weights->data->at(i)->second->val;
	E1.w = w;
	E2.w = w;
#endif
	g->edges[from]->push_back(E1);
	g->edges[to]->push_back(E2);
      }
      pppgraph_map[s] = g;
    } // end of graph processing
    else if( (*graph)[*v].op == Algorithm ) {
      std::string a_name = (*revTable)[*v];
      _algorithm *  alg = (*AlgTable)[a_name];
#ifdef Weight
      PPPWGraph * G_struct= pppgraph_map[alg->gname];
#else
      PPPGraph * G_struct = pppgraph_map[alg->gname];
#endif
      if (alg->algid == Gbfs) {
#ifndef Weight
	call_bfs(G_struct, alg->val_to_start, Q);
#endif
      } else if (alg->algid == Gmst) {
      } else {
	fprintf(stderr,"Algorithm Not Defined");
	exit(EXIT_FAILURE);
      }	  
    }
  }
  Q->wait_for_threads();
}
